/**
 * Copyright 2010 Victor Egea Hernando
 *
 * RockScript is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 * 
 * RockScript is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with RockScript.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "method.h"
#include "routine.h"

namespace paper{

method::method( const corelib::ustring &name, vm_class *pclass, 
	corelib::uint32 midx, const corelib::ustring &meta, corelib::uint32 nargs ){
    _idx = midx; _nargs = nargs; _name = name; 
    _sfstack = SP_NO_LOCAL_EXP_REG;
    _pclass = pclass; _flags = 0;
	_meta_name = meta + name;
	_mptr = corelib::null;
}

method::~method(){
    //dtor
}

void method::set_cpp_handler( cpp_method ptr ){
	_mptr = ptr;
	// set/clear FLG_MTHD_CPP
	if( _mptr != corelib::null ){
    	FLAGS_SET( _flags, FLG_MTHD_CPP );
	}else{
    	FLAGS_OFF( _flags, FLG_MTHD_CPP );
	}
}

void method::set_flags( corelib::uint32 flags ){
    FLAGS_SET( _flags, flags );
}

bool method::set_stack_frame_size( corelib::uint32 nlvars, corelib::uint32 neregs ){
    _sfstack = nlvars + neregs + SP_NO_LOCAL_EXP_REG;
    // (useful_frame <= 2^15) && (neregs_ <= 2^8)
    return ( _sfstack - SP_CONTEXT_REGS <= PWRTWO(15) ) && ( neregs <= PWRTWO(8) ); 
}

bool method::add_inst_b( corelib::uint8 op, corelib::uint8 a, corelib::int16 z ){
    _opcode.push_back( instruction( op, a, z ).bin() );
	return true;
}

bool method::add_inst_a( corelib::uint8 op, corelib::uint8 a, corelib::uint8 b, corelib::uint8 c ){
	if( op==OP_NEW && ( a<=10 || a>42 ) )
		return false;
    _opcode.push_back( instruction( op, a, b, c ).bin() );
	return true;
}

corelib::uint32 method::add_constant( const __register &reg )
{
	_constant.push_back( reg );
	return _constant.size() - 1;
}

}; // namespace paper

std::ostream &operator << ( std::ostream &os, const paper::method &method )
{
	return os << method.pclass()->name() << "::" << method.meta_name();
}

